# 分页爬取豆瓣网图书Top250信息，并分别使用三种网页信息解析库（Xpath，BeautifulSoup，PyQuery），并将信息写入文件中
# 第八周作业1)
# 班级：Python五期
# 学员：李子坚

from requests.exceptions import RequestException
from lxml import etree
from bs4 import BeautifulSoup
from pyquery import PyQuery
import requests
import time,json
import os

def getPage(url):
    '''爬取指定url地址的信息'''
    try:
        #定义请求头信息
        headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36'}
        #执行爬取
        res = requests.get(url,headers=headers)
        #判断并返回结果
        if res.status_code == 200:
            return res.text
        else:
            return None
    except RequestException:	
        return None

def parsePage(content, offset, option):
    '''解析爬取网页中内容，并返回结果'''
    #print(content)
    index = offset

    if option == '1':
        #========使用Xpath解析======================
        #初始化，返回根节点对象
        html = etree.HTML(content)
        #解析网页中<tr class="item">....</tr>信息（一本本图书信息）
        items = html.xpath("//tr[@class='item']")
        #遍历并解析每本图书具体信息
        for item in items:
            index += 1
            pub_info = item.xpath(".//p[@class='pl']/text()")[0]
            pub_list = pub_info.split("/")
            price = pub_list.pop()          #价格
            pubtime = pub_list.pop()        #出版时间
            yield {
                'index':str(index),
                'title':item.xpath(".//div[@class='pl2']//a/@title")[0],
                #'orgtitle':item.xpath(".//td[2]//div[@class='pl2']//span/text()")[0],
                'image':item.xpath(".//a[@class='nbg']//img[@width='90']/@src")[0],
                'writer':("/").join(pub_list),
                'pubtime':pubtime,
                'price':price,
                'score':item.xpath(".//span[@class='rating_nums']/text()")[0],
                #'comment':item.xpath(".//p[@class='quote']//span[@class='inq']/text()")[0]
            }
            
    elif option == '2':
        #========使用BeautifulSoup解析======================
        #初始化，返回BeautifulSoup对象
        soup = BeautifulSoup(content,'lxml')
        #解析网页中<tr class="item">....</tr>信息（一本本图书信息）
        items = soup.find_all(name="tr",attrs={"class":"item"})
        #遍历并解析每本图书具体信息
        for item in items:
            index += 1
            pub_info = item.select("p.pl")[0].get_text()
            pub_list = pub_info.split("/")
            price = pub_list.pop()          #价格
            pubtime = pub_list.pop()        #出版时间
            yield {
                'index':str(index),
                'title':item.select("div.pl2 a")[0].attrs['title'],
                'image':item.select("a.nbg img")[0].attrs['src'],
                'writer':("/").join(pub_list),
                'pubtime':pubtime,
                'price':price,
                'score':item.select("div.star span.rating_nums")[0].string,
            }
            
    else:               #option == '3'        
        #========使用pyquery解析======================
        #初始化，返回Pyquery对象
        doc = PyQuery(content)
        #解析网页中<tr class="item">....</tr>信息（一本本图书信息）
        items = doc("tr.item")
        #遍历并解析每本图书具体信息
        for item in items.items():
            index += 1
            pub_info = item.find("p.pl").text()
            pub_list = pub_info.split("/")
            price = pub_list.pop()          #价格
            pubtime = pub_list.pop()        #出版时间
            yield {
                'index':str(index),
                'title':item.find('div.pl2 a').attr('title'),
                'image':item.find("a.nbg img").attr('src'),
                'writer':("/").join(pub_list),
                'pubtime':pubtime,
                'price':price,
                'score':item.find("div.star span.rating_nums").text(),
            }
    

def writeFile(content):
    '''执行文件追加写操作'''
    with open("./doubanbook.txt",'a',encoding="utf-8") as f:
        f.write(json.dumps(content,ensure_ascii=False).replace("\"","")+"\n")

def main(page, option):
    '''主程序函数，负责调度执行爬取处理'''
    #输出每页标题行
    print("%s%s%d%s%s"%("="*88,"第",page+1,"页","="*88))
    print("{:<4}{:<60}{:<30}{:<44}{:<8}{:<8}{:<6}".format("序号","图片","书名","作者/出版社","出版时间","价格","评分"))

    offset = page*25
    url = 'https://book.douban.com/top250?start='+str(offset)
    html = getPage(url) #执行爬取
    if html:
        #爬取内容逐行输出到文件
        for item in parsePage(html, offset, option): #执行解析并遍历
            #逐行输出图书信息
            item_info = "{:<6}{:<62}{:<30}{:<35}{:<12}{:<9}{:<6}".format(item['index'],item['image'],item['title'],item['writer'],item['pubtime'],item['price'],item['score'])
            print(item_info)
            writeFile(item_info) #执行写操作

#判断当前执行是否为主程序，并遍历调度主函数来爬取信息
if __name__ == '__main__':

    while True:
        #选择网页解析库
        option = input("请选择要使用的网页解析库（1-Xpath，2-BeautifulSoup，3-PyQuery，q-退出）：")
        if option == 'q' or option == 'Q':
            break
        elif option in ['1','2','3']:
            print("亲，正在下载豆瓣网图书Top250的图书信息，请稍候……")

            #判断当前文件夹下输出文件doubanbook.txt是否存在，如果已存在则删除
            if os.path.exists("./doubanbook.txt"):
                os.remove("./doubanbook.txt")
            #输出标题行
            writeFile("{:<4}{:<60}{:<30}{:<44}{:<8}{:<8}{:<6}".format("序号","图片","书名","作者/出版社","出版时间","价格","评分"))

            #开始爬取网页数据
            #main(0, option)
            for i in range(10):
                main(i, option)
                time.sleep(1)

            print("=======豆瓣网图书Top250的图书信息下载完成！=======")
            print("=======请查看图书信息文件<doubanbook.txt>！=======")

        else:
            print("亲，您的选项无效，请重新选择！")
